<?php
class spiderMan {
    /**
     * 爬虫版本
     */
    const V = '1.0.0';

    /**
     * 访问超时时间 单位s
     */
    const TIMEOUT = 0;

    /**
     * 爬取间隔时间 单位s
     */
    const INTERVAL = 0;

    /**
     * 最多尝试次数
     */
    const TRY_TIMES = 3;

    /**
     * 默认爬取深度
     */
    const DEPTH = 1;
    /**
     * PC端 headers agent
     */
    const PC  = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36';

    /**
     * Android端 headers agent
     */
    const ADR = 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_3_3 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13G34 Safari/601.1';

    /**
     * IOS端 headers agent
     */
    const IOS = 'Mozilla/5.0 (Linux; U; Android 6.0.1;zh_cn; Le X820 Build/FEXCNFN5801507014S) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/49.0.0.0 Mobile Safari/537.36 EUI Browser/5.8.015S';

    /**
     * 是否显示日志
     * @var
     */
    protected $showLog;

    /**
     * 日志文件路径
     * @var
     */
    protected $logFile;

    protected $startTime;

    /**
     * 获取字段设置
     * @var array
     */
    protected $fields = [];

    /**
     * 数据库设置
     * @var
     */
    protected $db;

    /**
     * 缓存工具 redis设置
     * @var
     */
    protected $redis;

    /**
     * 任务数
     * @var int
     */
    protected $taskNum = 1;

    /**
     * 当前任务ID
     * @var
     */
    protected $taskID;

    /**
     * 守护进程
     * @var bool
     */
    protected $stateStatic = false;

    /**
     * 多服务
     * @var bool
     */
    protected $multiServer = false;

    /**
     * 代理设置
     * @var array
     */
    protected $proxies = [];

    /**
     * 爬去终端
     * @var array
     */
    protected $agent   = [];

    /**
     * 终端IP地址设置
     * @var array
     */
    protected $clientIP = [];

    /**
     * 爬取间隔时间设置
     * @var
     */
    protected $interval;

    /**
     * 爬取超时时间设置
     * @var
     */
    protected $timeout;

    /**
     * 任务名称
     * @var
     */
    protected $name;

    /**
     * 尝试次数设置
     * @var
     */
    protected $tryTimes;

    /**
     * 爬取深度
     * @var
     */
    protected $depth;

    /**
     * 爬取字段
     * @var array
     */
    protected $export = [];

    /**
     * 当前服务器ID
     * @var
     */
    protected $serverID;

    /**
     * 停止标志
     * @var bool
     */
    protected $shutDown = false;

    /**
     * 处理特殊情况闭包函数
     * @var array
     */
    protected $dealPackages = [];

    /**
     * 构建函数，引入设置，配置类
     * spiderMan constructor.
     * @param array $config
     */
    public function __construct(array $config)
    {
        //获取 日志配置
        isset($config['log']) AND $this->logConfig($config['log']);
        //没有 任务配置 则报错
        !isset($config['mission']) AND $this->error('No mission config.');
        //获取 任务配置
        $this->missionConfig($config['mission']);
    }

    /**
     * 添加特殊内容处理函数
     * @param $name
     * @param $function
     */
    public function addPackages($name, $function)
    {
        if (!key_exists($name, $this->dealPackages)) {
            $this->dealPackages[$name] = $function;
        }
    }

    /**
     * 运行爬虫
     */
    public function run()
    {
        $this->parseCommand();
    }

    /**
     * 解析命令
     */
    protected function parseCommand()
    {
        //全局变量
        global $argv;
        //运行文件
        $runFile = $argv[0];
        //命令
        $command = isset($argv[1]) ? trim($argv[1]) : 'run';
        //子命令
        $subCommand = isset($argv[2]) ? $argv[2] : '';
        //命令判断
        switch ($command) {
            case 'run' :
                //运行
                break;
            case 'shutdown' :
                //停止
                break;
            case 'kill' :
                //杀死进程
                break;
            case 'status' :
                //显示运行状态
                break;
            default :
                //未知命令，报错
                $this->error('Unknown command! Please use run|shutdown|kill|status');
                break;
        }

    }
    /**
     * 获取 任务配置
     * @param array $missionConfig
     */
    protected function missionConfig(array $missionConfig)
    {
        //获取任务名称
        isset($missionConfig['name']) AND $this->name = $missionConfig['name'];

        //判断字段设置
        !isset($missionConfig['fields']) AND $this->error('No Fields config.');
    }

    /**
     * 获取 服务器配置
     * @param array $serverConfig
     */
    protected function serverConfig(array $serverConfig)
    {
        //获取字段设置
        $this->fields = $serverConfig['fields'];

        //获取 多任务开关
        $this->multiServer = isset($serverConfig['multiServer']) ? $serverConfig['multiServer'] : false;

        //如果打开，则配置数量
        if ($this->multiServer) {
            //获取 多任务数量
            $this->taskNum = isset($serverConfig['taskNum']) ? $serverConfig['taskNum'] : 1;
        }

        //获取 保存运行状态开关
        $this->stateStatic = isset($serverConfig['stateStatic']) ? $serverConfig['stateStatic'] : false;

        //获取当前服务ID
        $this->serverID = isset($serverConfig['serverID']) ? $serverConfig['serverID'] : rand(1,999);

        //查看是否有数据库配置
        !isset($serverConfig['db']) AND $this->error('No db config.');

        //获取数据库配置
        $this->db = $serverConfig['db'];

        //缓存redis设置
        isset($serverConfig['redis']) AND $this->db = $serverConfig['redis'];

        //获取代理设置
        isset($serverConfig['proxies']) AND $this->proxies = $serverConfig['proxies'];

        //获取终端设置
        $this->agent = isset($serverConfig['agent']) ? $serverConfig['agent'] : self::PC;

        //获取终端IP
        isset($serverConfig['clientIP']) AND $this->clientIP = $serverConfig['clientIP'];

        //获取间隔时间
        $this->interval = isset($serverConfig['interval']) ? $serverConfig['interval'] : self::INTERVAL;

        //获取超时时间
        $this->timeout = isset($serverConfig['timeout']) ? $serverConfig['timeout'] : self::TIMEOUT;

        //获取尝试次数
        $this->tryTimes = isset($serverConfig['tryTimes']) ? $serverConfig['tryTimes'] : self::TRY_TIMES;

        //获取爬取深度
        $this->depth = isset($serverConfig['depth']) ? $serverConfig['depth'] : self::DEPTH;
    }

    /**
     * 获取 日志配置
     * @param array $logConfig
     */
    protected function logConfig(array $logConfig)
    {
        //设置是否显示日志
        $this->showLog = isset($logConfig['show']) ? (bool)$logConfig['show'] : true;
        //设置路径
        $this->logFile = isset($logConfig['file']) ? $logConfig['file'] : '';
    }

    /**
     * 报错方法
     * @param $msg
     */
    protected function error ($msg) {
        $this->report($msg, 'danger');
    }

    /**
     * 提示方法
     * @param $msg
     * @param string $cssType
     */
    protected function report ($msg, $cssType = 'default')
    {
        //修饰开始 和 结束
        $cssStart = $cssEnd = "\033[0m";

        switch ($cssType) {
            case 'primary' :
                //紫字白底
                $cssStart = "\033[35;37m";
                break;
            case 'info'    :
                //蓝字
                $cssStart = "\033[34m";
                break;
            case 'warning' :
                //棕字
                $cssStart = "\033[33m";
                break;
            case 'success' :
                //绿字
                $cssStart = "\033[32m";
                break;
            case 'danger'  :
                //红字
                $cssStart = "\033[31m";
                break;
            default :break;
        }

        exit( "$cssStart [$cssType]$cssEnd:$msg\n" );
    }
}